//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2007
//
// 'Trim' tool.
//

# include "StdAfx.h"
# include "Resource.h"
# include "Tool.h"
# include "Map.h"
# include "Types.h"
# include "MapView.h"
# include "Load.h"
# include "Position.h"
# include "Scale.h"
# include "Menu.h"
# include "PtAlgo.h"
# include "TrimMask.h"
# include "EditRect.h"
# include "Globals.h"

class CTrimTool : public CTool {
  public:
	CTrimTool () : CTool (toolTrim) {}

	virtual bool Init ();
	virtual void Destroy ();

	virtual void OnActivate ();
	virtual void OnRemoveMap ();

	virtual void OnLDown   (int _x, int _y, DWORD _dwKeys);
	virtual void OnLUp     (int _x, int _y, DWORD _dwKeys);
	virtual void OnMove    (int _x, int _y, DWORD _dwKeys);
	virtual void OnRUp     (int _x, int _y, DWORD _dwKeys);

	virtual void OnPaint (HDC _hDC, const RECT & _rect);

	virtual void OnCtxMenu (int _x, int _y);

	virtual bool OnCommand (WORD _wID);
};

DECLARE_TOOL (CTrimTool);

static HCURSOR g_hcurMask;
static HCURSOR g_hcurMaskDragV;
static HCURSOR g_hcurMaskDragH;

static HBRUSH g_hbrMask;
static HMENU g_hmenuMask;

static rect_t g_rectMask;

static enum {dmRect, dmX0, dmX1, dmY0, dmY1} g_dm;

bool CTrimTool::Init () {
	g_hcurMask      = ::LoadCursor (g_hInst, MAKEINTRESOURCE (IDC_CursorModeMask));
	g_hcurMaskDragV = ::LoadCursor (NULL, IDC_SIZENS);
	g_hcurMaskDragH = ::LoadCursor (NULL, IDC_SIZEWE);

	g_hbrMask = ::CreateSolidBrush (c_colGray);

	g_hmenuMask = ::GetSubMenu (LoadMenu (IDM_POPUP), smpTrim);
	::SetMenuDefaultItem (g_hmenuMask, ID_RECT_PROPERTIES, MF_BYCOMMAND);

	return true;
}

void CTrimTool::Destroy () {
	if (g_hbrMask)
		::DeleteObject (g_hbrMask);
}

void CTrimTool::OnActivate () {
	CTool::SetPermanentCursor (g_hcurMask);
}

void CTrimTool::OnRemoveMap () {
	g_rectMask = rect_t (0, 0, 0, 0);
}

static
void SetDragMode (const point_t & _pt) {
	const float c_fE = c_fE_in_pixels/g_kY;
	size_t cEdge = -1;
	if (! g_rectMask.Invalid () && FrameContainsPt (g_rectMask, _pt, c_fE, g_map.fCosY, & cEdge)) {
		switch (cEdge) {
			case 0:	g_dm = dmX0; CTool::SetPermanentCursor (g_hcurMaskDragH); break;
			case 1: g_dm = dmY1; CTool::SetPermanentCursor (g_hcurMaskDragV); break;
			case 2:	g_dm = dmX1; CTool::SetPermanentCursor (g_hcurMaskDragH); break;
			case 3: g_dm = dmY0; CTool::SetPermanentCursor (g_hcurMaskDragV); break;
		}
	} else {
		CTool::SetPermanentCursor (g_hcurMask);
		g_dm = dmRect;
	}
}

void CTrimTool::OnLDown (int _x, int _y, DWORD _dwKeys) {
	point_t pt;
	ScreenToPt (_x, _y, pt);

	SetDragMode (pt);

	if (g_dm == dmRect) {
		g_rectMask.x0 = g_rectMask.x1 = pt.x;
		g_rectMask.y0 = g_rectMask.y1 = pt.y;
	}

	StartDND (_x, _y);

	Redraw ();
}

void CTrimTool::OnLUp (int _x, int _y, DWORD _dwKeys) {
	if (! CTool::s_bDND)
		return;
	StopDND ();

	point_t pt;
	ScreenToPt (_x, _y, pt);

	switch (g_dm) {
		case dmRect: g_rectMask.x1 = pt.x; g_rectMask.y1 = pt.y; break;
		case dmX0:   g_rectMask.x0 = pt.x; break;
		case dmX1:   g_rectMask.x1 = pt.x; break;
		case dmY0:   g_rectMask.y0 = pt.y; break;
		case dmY1:   g_rectMask.y1 = pt.y; break;
		default:     assert (false);
	}

	// Normalize the rectangle.
	if (g_rectMask.x0 > g_rectMask.x1)
		std::swap (g_rectMask.x0, g_rectMask.x1);
	if (g_rectMask.y0 > g_rectMask.y1)
		std::swap (g_rectMask.y0, g_rectMask.y1);

	// Round the mask.
	if (g_map.Levels.size () >= 2)
		g_map.pTypeSet->pfRoundRect (g_map, g_map.Levels.size () - 2, g_rectMask);

	Redraw ();
}

void CTrimTool::OnMove (int _x, int _y, DWORD _dwKeys) {
	point_t pt;
	ScreenToPt (_x, _y, pt);

	if (! CTool::s_bDND) {
		SetDragMode (pt);
		return;
	}

	switch (g_dm) {
		case dmRect: g_rectMask.x1 = pt.x; g_rectMask.y1 = pt.y; break;
		case dmX0:   g_rectMask.x0 = pt.x; break;
		case dmX1:   g_rectMask.x1 = pt.x; break;
		case dmY0:   g_rectMask.y0 = pt.y; break;
		case dmY1:   g_rectMask.y1 = pt.y; break;

		default:     assert (false);
	}

	// Round the mask.
	if (g_map.Levels.size () >= 2)
		g_map.pTypeSet->pfRoundRect (g_map, g_map.Levels.size () - 2, g_rectMask);

	Redraw ();
}

void CTrimTool::OnRUp (int _x, int _y, DWORD _dwKeys) {
	CTrimTool::OnCtxMenu (_x, _y);
}

void CTrimTool::OnCtxMenu (int _x, int _y) {
	if (g_bLoading)
		return;

	if (
		g_rectMask.x0 == g_rectMask.x1 ||
		g_rectMask.y0 == g_rectMask.y1
	) {
		::EnableMenuItem (g_hmenuMask, ID_MASK_TRIM_OUTSIDE, MF_BYCOMMAND | MF_GRAYED);
//		::EnableMenuItem (g_hmenuMask, ID_MASK_TRIM_INSIDE,  MF_BYCOMMAND | MF_GRAYED);
	} else {
		::EnableMenuItem (g_hmenuMask, ID_MASK_TRIM_OUTSIDE, MF_BYCOMMAND | MF_ENABLED);
//		::EnableMenuItem (g_hmenuMask, ID_MASK_TRIM_INSIDE,  MF_BYCOMMAND | MF_GRAYED);//MF_ENABLED);
	}
	//::EnableMenuItem (g_hmenuMask, ID_RECT_PROPERTIES,  MF_BYCOMMAND | MF_ENABLED);
	PopupMenu (g_hmenuMask);
}

void CTrimTool::OnPaint (HDC _hDC, const RECT & _rect) {
	if (
		g_rectMask.x0 == g_rectMask.x1 ||
		g_rectMask.y0 == g_rectMask.y1
	)
		return;

	RECT rect;
	rect.left   = XToScreen (g_rectMask.x0);
	rect.right  = XToScreen (g_rectMask.x1);
	rect.top    = YToScreen (g_rectMask.y1);
	rect.bottom = YToScreen (g_rectMask.y0);
	if (rect.left > rect.right)
		std::swap (rect.left, rect.right);
	if (rect.top > rect.bottom)
		std::swap (rect.top, rect.bottom);

	::FrameRect (_hDC, & rect, g_hbrMask);
}

bool CTrimTool::OnCommand (WORD _wID) {
	switch (_wID) {
		case ID_MASK_TRIM_OUTSIDE:
			TrimMask (g_rectMask, false);
			return true;

		case ID_MASK_TRIM_INSIDE:
			TrimMask (g_rectMask, true);
			return true;

		case ID_RECT_PROPERTIES: {
			if (g_rectMask.Invalid ())
				return false;
			EditRect (g_hWnd, g_rectMask);
			Redraw ();
			return true;
		}
	}
	return false;
}
